﻿// Inner Fire 游戏引擎库
// static_string 静态字符串
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 一种string_view的改进版本。通过一个字符串内存池来控制字符串。
// 一但进入内存池之后，就无法变化。所以这也是非常危险的。
// 仅用于能够预测的项目。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-03-16

#pragma once

#include <EASTL/string_view.h>
#include <EASTL/vector.h>
#include <memory>
#include <string>
#include <klog.h>

// 是否记录没有找到的项目
#define LOG_UNABLE_FIND

namespace ikit {
class static_string_manager;

struct sstr {
public:
  sstr() : uid_(0) {}
  sstr(size_t uid) : uid_(uid) {}
  sstr(const char* text);
  sstr(const char* text, size_t len);
  // 拷贝构造函数
  sstr(const sstr& rhs) : uid_(rhs.uid_) {}
  ~sstr() {}

  // 返回是否为空
  inline bool empty() const { return uid_ == 0; }
  // 获得实际的Chars
  const char* c_str() const;
  // 查找一个符号
  int index_of(char c) const;
  int index_of(const char* text) const;
  // 裁剪一个项目
  sstr substr(size_t begin, size_t count = 0) const;
  // 将此项目转化为一个宽字符
  std::wstring to_wide() const;
  // 返回一个GBK字符（此项目需要分配内存空间，只在调试时打印使用）
  std::string gbk() const;
  // 如果字符串为空，则返回"undefined"，否则返回字符串
  const char* log_str() const { return empty() ? "undefined" : c_str(); }

  // 提供获取 uid_ 的方法（用于哈希函数）
  inline size_t uid() const { return uid_; }
  // 返回字符串的长度大小
  size_t size() const;

  // 重载比较运算符
  bool operator==(const sstr& rhs) const { return uid_ == rhs.uid_; }
  bool operator!=(const sstr& rhs) const { return uid_ != rhs.uid_; }

private:
  size_t uid_;

  friend class static_string_manager;
};

struct static_string_instance {
public:
  size_t uid;
  const char* pointer;
  size_t size;

  static_string_instance(const char* text);
  static_string_instance(const char* text, size_t len);
  static_string_instance(const eastl::string_view& text);
  static_string_instance(size_t uid, const char* pointer, size_t size);

  inline const char* c_str() const { return pointer; }

private:
  void set_by_string_view(const eastl::string_view& text);
};

class static_string_manager {
public:
  static_string_manager(int buffer_size);
  ~static_string_manager();

  // 根据文字创建一个static_string
  static_string_instance create(const char* text);
  // 根据文字创建一个static_string，指定大小，因为有时候会从项目中截取一段
  static_string_instance create(const char* text, size_t len);
  // 通过UID获得一个char
  const char* get_chars(sstr uid) const;
  // 通过UID获得一个实例
  const static_string_instance& get_instance(size_t uid) const;

private:
  // 新建一个内存块
  void create_new_buffer();

  // 用于字符串分配的内存
  eastl::vector<char*> buffers_;
  // 用于保存每个ID的项目
  eastl::vector<static_string_instance> strings_;

  char* current_buffer_;
  size_t current_pointer_;
  // 每一个内存块的大小
  size_t buffer_size_;
  // 用于保存UID
  size_t uid_record;
};

sstr get_string_uid(const char* text);
const char* get_chars(sstr uid);
std::string get_chars_to_gbk(sstr uid);

// 从一个列表中读取项目，每一个项目使用","号分割。不支持Trim，所以","号之间不能有任何空格。
eastl::vector<sstr> get_string_list(const char* text);
// 从一个类似于"Name:Value"这样带":"的名称中读取名称和值。可以没有值，只有名称，例如"Name"。
void get_name_value(const char* text, sstr& name, sstr& value);

// 通过名称获得项目
template <typename T>
static T* get_item_by_name(eastl::vector<std::unique_ptr<T>>& list,
    ikit::sstr name, T* default_item = nullptr) {
  if (name.empty()) return default_item;

  for (auto& e : list) {
    if (e->name == name) {
      return e.get();
    }
  }

#ifdef LOG_UNABLE_FIND
  ikit::log("Unable find \"%s\" (%s)", name.c_str(), typeid(T).name());
#endif // LOG_UNABLE_FIND

  return default_item;
}

// 通过名称获得项目
template <typename T>
static T* get_item_by_name(
    eastl::vector<T*>& list, ikit::sstr name, T* default_item = nullptr) {
  if (name.empty()) return default_item;

  for (auto e : list) {
    if (e->name == name) {
      return e;
    }
  }
  
#ifdef LOG_UNABLE_FIND
  ikit::log("Unable find \"%s\" (%s)", name.c_str(), typeid(T).name());
#endif // LOG_UNABLE_FIND

  return default_item;
}

} // namespace ikit